<?php defined('SYSPATH') or die('No direct script access.');
/**
 * 支付类
 *
 * @author  Yellow.Chow <aultoale@gmail.com>
 * @version $Id: payment.php 225 2012-05-31 02:49:33Z yellow.chow $
 * @license http://www.gnu.org/licenses/gpl-3.0.html    GPL 3
 */
class Payment
{

    const STAT_INITED    = 0; // 初始状态，未确认
    const STAT_CONFIRMED = 1; // 已确认
    const STAT_TREATMENT = 2; // 处理中
    const STAT_PAID      = 3; // 已付款
    const STAT_SHIPPED   = 4; // 已发货
    const STAT_RECEIVED  = 5; // 已收货
    const STAT_SUCCEED   = 6; // 已完成
    const STAT_FAILED    = 7; // 失败
    const STAT_TIMEOUT   = 8; // 超时
    const STAT_CANCELED  = 9; // 已取消

    /**
     * 创建支付方式
     *
     * @param  string  $adapter
     * @param  array   $config
     * @return Payment_Adapter
     * @throws Payment_Exception
     */
    public static function factory($adapter, array $config = array())
    {
        $class = "Payment_Adapter_".implode('_', array_map('ucfirst', explode('_', $adapter)));
        if (! class_exists($class))
        {
            throw new Payment_Exception('不支持的支付方式 ":adapter"',
                array(':adapter' => $adapter));
        }

        $instance = new $class($config);
        if ( ! $instance instanceof Payment_Adapter)
        {
            throw new Payment_Exception("支付方式适配器 '$class' 必须从 Payment_Adapter 继承");
        }

        return $instance;
    }

    /**
     * 创建支付响应
     *
     * @param  string  $adapter
     * @return Payment_Respond
     * @throws Payment_Exception
     */
    public static function respond($payment)
    {
        $class = "Payment_Respond_".implode('_', array_map('ucfirst', explode('_', $payment)));
        if ( ! class_exists($class))
        {
            throw new Payment_Exception('不支持的支付响应方式 :payment',
                array(':adapter' => $payment));
        }

        $instance = new $class;
        if ( ! $instance instanceof Payment_Respond)
        {
            throw new Payment_Exception("支付响应类 '$class' 必须从 Payment_Respond 继承");
        }

        return $instance;
    }

    /**
     * 写入支付日志
     *
     * @param  string  $adapter
     */
    public static function log($adapter)
    {
        $covert = (bool) preg_match('/(tenpay|yeepay)/i', $adapter); // 判断是否编码转换

        $data = array(
            'payment'     => $adapter,
            'log_time'    => time(),
            'client_ip'   => Request::$client_ip,
            'method'      => strtoupper(Request::$initial->method()),
            'request_uri' => URL::scheme().'://'.URL::host().URL::current(),
            'envs'        => serialize(self::_convert(self::_filter($_SERVER), $covert)),
            'data'        => serialize(self::_convert(Request::$initial->is_post() ? $_POST : $_GET, $covert)),
        );
        DB::insert('payment_logs', $data)->execute();

        if (mt_rand(0, 20) == 1) // 删除 1 个月前的支付日志
        {
            DB::delete('payment_logs')
                ->where('log_time', '<', strtotime('-1 month'))
                ->execute();
        }
    }

    /**
     * 格式化/转换日志数据
     *
     * @param  mixed  $data
     * @param  bool   $covert
     * @return mixed
     */
    protected static function _convert($data, $covert = FALSE)
    {
        if ($covert)
        {
            if (is_array($data))
            {
                foreach ($data as $key => & $value)
                {
                    $value = self::_convert($value, $covert);
                }
            }
            else
            {
                $data = mb_convert_encoding($data, 'UTF-8', 'GBK');
            }
        }

        return $data;
    }

    /**
     * 过滤环境参数
     *
     * @param  array  $data
     * @return array
     */
    protected static function _filter(array $data)
    {
        $cols = array(
            'QUERY_STRING', 'CONTENT_TYPE', 'CONTENT_LENGTH', 'REQUEST_METHOD',
            'REQUEST_URI', 'REQUEST_TIME', 'REMOTE_ADDR', 'REMOTE_PORT',
            'REDIRECT_STATUS', 'REDIRECT_URL', 'HTTP_X_REAL_IP',
            'HTTP_X_FORWARDED_FOR', 'HTTP_X_REQUESTED_WITH', 'HTTP_HOST',
            'HTTP_CLIENT_IP', 'HTTP_USER_AGENT', 'HTTP_REFERER', 'PATH_INFO',
        );

        $result = array();
        foreach ($data as $key => $val)
        {
            if (in_array(strtoupper($key), $cols))
            {
                $result[$key] = $val;
            }
        }

        return $result;
    }

}
